import hashlib
import hmac
from datetime import datetime
from typing import Dict, Any

import jwt
from fastapi import Request, HTTPException, Depends
from fastapi.security import OAuth2PasswordBearer
from pydantic import BaseModel, Field

# 定义密钥和算法
SECRET_KEY = "yilun142352"
# 算法
ALGORITHM = "HS256"
# 超时时间
ACCESS_TOKEN_EXPIRE_MINUTES = 30

# 定义 OAuth2 方案
oauth2_scheme = OAuth2PasswordBearer(tokenUrl="/token")


def get_current_user(token: str):
    print(token)
    # 1.拆分token
    verify = token.split(" ")[1]
    tokenVerify = EncryptionMiddleware.decrypt_token(verify)
    return tokenVerify.user_id


# token
class TokenVerify(BaseModel):
    user_id: int = Field(default=None)
    user_name: str = Field(default=None)


# sign
class SignVerify(BaseModel):
    secret_key: str = Field(default=None)
    timestamp: int = Field(default=None)
    expire_seconds: int = Field(default=30, description="有效时间")


class EncryptionMiddleware:
    @staticmethod
    def get_current_user(token: str):
        '''
        获取当前用户id
        :param token:
        :return:
        '''
        try:
            user = EncryptionMiddleware.decrypt_token(token)
            user_id = user["user_id"]
            return user_id
        except Exception as e:
            raise Exception("令牌过期")

    @staticmethod
    def get_current_username(token: str):
        '''获取当前用户'''
        try:
            user = EncryptionMiddleware.decrypt_token(token)
            return user
        except Exception as e:
            raise Exception("令牌过期")

    # 加密 token
    @staticmethod
    def encrypt_token(tokenVerify: TokenVerify):
        '''
        加密token
        :param tokenVerify:
        :return:
        '''
        verify = {"user_id": tokenVerify.user_id, "user_name": tokenVerify.user_name}
        token = jwt.encode(verify, SECRET_KEY, algorithm=ALGORITHM)
        return token

    # 解密token
    @staticmethod
    def decrypt_token(token: str):
        '''
        解密token
        :param token:
        :return:
        '''
        verify = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        return verify

    # 验证token是否合法
    @staticmethod
    def verify_token(token: str):
        verify = jwt.decode(token, SECRET_KEY, algorithms=[ALGORITHM])
        if verify["user_id"] or verify["user_name"]:
            return True
        return False

    @staticmethod
    def generate_signature(
            self,
            params: Dict[str, Any],
            headers: Dict[str, str],
            timestamp: int
    ) -> str:
        """
        生成请求签名
        :param params: 请求参数（GET/POST）
        :param headers: 需要参与签名的请求头
        :param timestamp: 当前时间戳（秒级）
        """
        # 1. 按字段名排序后拼接键值对
        sorted_params = self._sort_and_join(params)
        sorted_headers = self._sort_and_join(headers)

        # 2. 拼接所有数据
        sign_str = f"{timestamp}|{sorted_params}|{sorted_headers}"

        # 3. 使用HMAC-SHA256生成签名
        return hmac.new(
            self.secret_key.encode(),
            sign_str.encode(),
            hashlib.sha256
        ).hexdigest()

    @staticmethod
    def verify_request(
            self,
            request: Request,
            sign_header: str = "X-Sign",
            timestamp_header: str = "X-Timestamp"
    ) -> bool:
        """
        验证请求签名是否有效
        :param request: FastAPI Request对象
        :param sign_header: 签名请求头名称
        :param timestamp_header: 时间戳请求头名称
        :raises HTTPException: 验证失败时抛出
        """
        # 1. 获取必要请求头
        sign = request.headers.get(sign_header)
        timestamp = request.headers.get(timestamp_header)

        if not sign or not timestamp:
            raise HTTPException(403, "Missing signature headers")

        try:
            timestamp = int(timestamp)
        except ValueError:
            raise HTTPException(403, "Invalid timestamp format")

        # 2. 检查时间戳有效期
        now = int(datetime.now().timestamp())
        if abs(now - timestamp) > self.expire_seconds:
            raise HTTPException(403, "Signature expired")

        # 3. 获取请求参数
        params = {}
        if request.method == "GET":
            params = dict(request.query_params)
        else:
            try:
                params = request.json()
            except:
                pass  # 非JSON请求体忽略

        # 4. 参与签名的请求头（按需选择）
        sign_headers = {
            "user-agent": request.headers.get("user-agent", ""),
            "content-type": request.headers.get("content-type", "")
        }

        # 5. 重新计算签名并比对
        expected_sign = self.generate_signature(
            params=params,
            headers=sign_headers,
            timestamp=timestamp
        )

        if not hmac.compare_digest(expected_sign, sign):
            raise HTTPException(403, "Invalid signature")

        return True

    @staticmethod
    def _sort_and_join(data: Dict[str, Any]) -> str:
        """辅助方法：排序后拼接键值对"""
        return "&".join(
            f"{k}={v}"
            for k, v in sorted(data.items())
            if v is not None  # 过滤None值
        )
